#include <fstream>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>
#include <map>
#include <lapacke.h>
#include "Function.h"


class TimeIntegrator{
public:
    double T;
    double k;
    virtual Vec<double,6> Implement(const Vec<double,6> &u0,const Function &f,const JacobiFunction &ja,int p = 1,bool ISOUT = false, std::string filename = "out.data") = 0;
    virtual ~TimeIntegrator(){}
    Vec<double,6> Newton(const Vec<double,6> &x,const Function &f,const JacobiFunction &ja,const double betas,const Vec<double,6> &res,double eps = 1e-10);
    Vec<double,6> nextx(const Vec<double,6> &x,const Function &f,const JacobiFunction &ja,const double betas,const Vec<double,6> &res);
    double maxnorm(const Vec<double,6> &x);
};

typedef TimeIntegrator* (*CreateFn)();

class AdamsBashforth : public TimeIntegrator{
public:
    Vec<double,6> Implement(const Vec<double,6> &u0,const Function &f,const JacobiFunction &ja,int p = 1,bool ISOUT = false, std::string filename = "out.data");
    static TimeIntegrator * Create(){return new AdamsBashforth();}
};

class AdamsMoulton : public TimeIntegrator{
public:
    Vec<double,6> Implement(const Vec<double,6> &u0,const Function &f,const JacobiFunction &ja,int p = 1,bool ISOUT = false, std::string filename = "out.data");
    static TimeIntegrator * Create(){return new AdamsMoulton();}
};

class BDF : public TimeIntegrator{
public:
    Vec<double,6> Implement(const Vec<double,6> &u0,const Function &f,const JacobiFunction &ja,int p = 1,bool ISOUT = false, std::string filename = "out.data");
    static TimeIntegrator * Create(){return new BDF();}
};

class RungeKutta : public TimeIntegrator{
public:
    Vec<double,6> Implement(const Vec<double,6> &u0,const Function &f,const JacobiFunction &ja,int p = 1,bool ISOUT = false, std::string filename = "out.data");
    static TimeIntegrator * Create(){return new RungeKutta();}
};
